package model;

import enums.ExtensionEnum;
import enums.FigureEnum;
import enums.PremisaTypeEnum;
import enums.SylogismReduceModesEnum;

import java.io.Serializable;
/*

    This file is part of Logica-Logike.

    Logica-Logike is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation version 3 of the License.

    Logica-Logike is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Logica-Logike.  If not, see <http://www.gnu.org/licenses/>.

 */
/**
 * Modela un silogismo;
 * @author Jose Martin Rozanec;
 */
public class Sylogism implements Serializable {
    private Premisa premisaMayor;
    private Premisa premisaMenor;
    private Premisa conclusion;
    private boolean[] violations;

    /**
     * Permite setear una premisa;
     *
     * @param premisa;
     * @param premisaType;
     */
    public void setPremisa(Premisa premisa, PremisaTypeEnum premisaType) {
        switch (premisaType) {
            case FIRST:
                premisaMayor = premisa;
                break;
            case SECOND:
                premisaMenor = premisa;
                break;
            case CONCLUSION:
                conclusion = premisa;
                break;
        }
    }

    /**
     * Identifica la figura del silogismo;
     *
     * @return FigureEnum;
     */
    public FigureEnum getFigure() {
        if (premisaMayor != null && premisaMenor != null) {
            if (premisaMayor.getFirstTerm()!=null && premisaMayor.getFirstTerm().equalsIgnoreCase(premisaMenor.getSecondTerm())) {
                return FigureEnum.FIRST;
            } else {
                if (premisaMayor.getSecondTerm()!=null && premisaMayor.getSecondTerm().equalsIgnoreCase(premisaMenor.getSecondTerm())) {
                    return FigureEnum.SECOND;
                } else {
                    if (premisaMayor.getFirstTerm()!=null && premisaMayor.getFirstTerm().equalsIgnoreCase(premisaMenor.getFirstTerm())) {
                        return FigureEnum.THIRD;
                    } else {
                        if (premisaMayor.getSecondTerm()!=null && premisaMayor.getSecondTerm().equalsIgnoreCase(premisaMenor.getFirstTerm())) {
                            return FigureEnum.FOURTH;
                        }
                    }
                }
            }
        }
        return FigureEnum.NONE;
    }

    /**
     * Devuelve sugerencias respecto a como formar un silogismo valdo;
     *
     * @return String;
     */
    public String getPremisaSuggestion() {
        if (premisaMayor != null) {//si la premisa mayor no es null
            if (premisaMenor != null) {//PREMISA MAYOR Y MENOR NO NULAS, CONCLUSION NULA
                if (conclusion == null || Premisa.isComplete(conclusion.toString())) {
                    return premisaMayorYPremisaMenor();
                }
            } else {
                if (conclusion == null) {//premisa mayor no nula, premisa menor y conclusion nulas
                    return premisaMayor();
                } else {//premisa mayor y conclusion no nulas, premisa menor nula
                    return premisaMayorYConclusion();
                }
            }
        } else {//premisa mayor nula
            if (premisaMenor != null) {
                if (conclusion != null) {//premisa Menor y conclusion
                    return premisaMenorYConclusion();
                } else {//premisa mayor y conclusion nulas; premisa menor no nula
                    return premisaMenor();
                }
            } else {//premisa mayor y menor nulas;
                if (conclusion != null) {//conclusion no nula
                    return conclusion();
                } else {//todas las premisas son nulas
                    return MethodsLibrary.resourceBundle.getString(BundleExpressions.ALL_EXTENSION_MODES_PRIMERA_FIGURA)
                            + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.ALL_EXTENSION_MODES_SEGUNDA_FIGURA)
                            + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.ALL_EXTENSION_MODES_TERCERA_FIGURA)
                            + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.ALL_EXTENSION_MODES_CUARTA_FIGURA);
                }
            }
        }
        return MethodsLibrary.resourceBundle.getString(BundleExpressions.SUGGESTION_NOT_FOUND);
    }

    /**
     * Da a conocer si el silogismo se halla completo o no;
     *
     * @return boolean;
     */
    public boolean isComplete() {//se asume que solamente se asigna una premisa, si la forma de la misma es valida
        if (premisaMayor != null && premisaMenor != null && conclusion != null) {
            return true;
        }
        return false;
    }

    /**
     * Permite obtener el termino mayor del silogismo;
     *
     * @return String;
     */
    public String getTerminoMayor() {
        String terminoMedio = getTerminoMedio();
        if (!terminoMedio.equals("") && premisaMayor != null) {
            if (premisaMayor.getFirstTerm().equalsIgnoreCase(terminoMedio)) {
                return premisaMayor.getSecondTerm();
            } else {
                return premisaMayor.getFirstTerm();
            }
        } else {
            if (conclusion != null) {
                return conclusion.getSecondTerm();
            }
        }
        return "";
    }

    /**
     * Permite obtener el termino medio del silogismo;
     *
     * @return String;
     */
    public String getTerminoMedio() {
        if (premisaMenor != null && premisaMayor != null) {
            if ((premisaMenor.getFirstTerm()!=null&&premisaMenor.getFirstTerm().equalsIgnoreCase(premisaMayor.getFirstTerm())) ||
                    (premisaMenor.getFirstTerm()!=null && premisaMenor.getFirstTerm().equalsIgnoreCase(premisaMayor.getSecondTerm()))) {
                return premisaMenor.getFirstTerm();
            } else {
                if ((premisaMenor.getSecondTerm()!=null&&premisaMenor.getSecondTerm().equalsIgnoreCase(premisaMayor.getFirstTerm())) ||
                        (premisaMenor.getSecondTerm()!=null && premisaMenor.getSecondTerm().equalsIgnoreCase(premisaMayor.getSecondTerm()))) {
                    return premisaMenor.getSecondTerm();
                }
            }
        } else {
            if (conclusion != null) {
                if (premisaMayor != null) {
                    if (premisaMayor != null) {
                        if ((premisaMayor.getFirstTerm()!=null&&premisaMayor.getFirstTerm().equalsIgnoreCase(conclusion.getFirstTerm())) ||
                                (premisaMayor.getFirstTerm()!=null && premisaMayor.getFirstTerm().equalsIgnoreCase(conclusion.getSecondTerm()))) {
                            return premisaMayor.getSecondTerm();
                        } else {
                            return premisaMayor.getFirstTerm();
                        }
                    }
                } else {
                    if (premisaMenor != null) {
                        if (premisaMenor.getFirstTerm().equalsIgnoreCase(conclusion.getFirstTerm()) ||
                                premisaMenor.getFirstTerm().equalsIgnoreCase(conclusion.getSecondTerm())) {
                            return premisaMenor.getSecondTerm();
                        } else {
                            return premisaMenor.getFirstTerm();
                        }
                    }
                }
            }
        }
        return "";
    }

    /**
     * Permite obtener el termino menor del silogismo;
     *
     * @return String;
     */
    public String getTerminoMenor() {
        String terminoMedio = getTerminoMedio();
        if (!terminoMedio.equals("") && premisaMenor != null) {
            if (premisaMenor.getFirstTerm().equalsIgnoreCase(terminoMedio)) {
                return premisaMenor.getSecondTerm();
            } else {
                return premisaMenor.getFirstTerm();
            }
        } else {
            if (conclusion != null) {
                return conclusion.getFirstTerm();
            }
        }
        return "";
    }

    /**
     * Valida si el silogismo creado es correcto;
     *
     * @return boolean;
     */
    public boolean validate() {
        if (analize().equals("El silogismo ingresado es correcto!")) {
            return true;
        }
        return false;
    }

    /**
     * Analiza e informa las violaciones en que incurre el silogismo;
     *
     * @return String;
     */
    public String analize() {
        violations = new boolean[9];
        StringBuffer violaciones = new StringBuffer();
        if (isComplete()) {
            String terminoMayor = getTerminoMayor();
            String terminoMedio = getTerminoMedio();
            String terminoMenor = getTerminoMenor();
            if (!validateTerminosIguales() ||
                    (terminoMayor.equalsIgnoreCase(terminoMedio) ||
                            terminoMayor.equalsIgnoreCase(terminoMenor) ||
                            terminoMedio.equalsIgnoreCase(terminoMenor))) {
                violaciones.append("-Los terminos del silogismo deben ser tres: mayor[T], medio[M] y menor[m].\n");
                violations[0] = true;
            }
            if (premisaMayor.getFirstTerm().equalsIgnoreCase(getTerminoMayor())) {
                if (!premisaMayor.getTermExtension(true)) {
                    if (conclusion.getTermExtension(false)) {//termino mayor presenta mayor extension en la conclusion
                        violaciones.append("-El termino mayor [T] presenta mayor extension en la conclusion que en la premisa.\n");
                        violations[1] = true;
                    }
                }
            } else {
                if (!premisaMayor.getTermExtension(false)) {
                    if (conclusion.getTermExtension(false)) {//termino mayor presenta mayor extension en la conclusion
                        violaciones.append("-El termino mayor [T] presenta mayor extension en la conclusion que en la premisa.\n");
                        violations[1] = true;
                    }
                }
            }
            if (premisaMenor.getFirstTerm().equalsIgnoreCase(getTerminoMenor())) {
                if (!premisaMenor.getTermExtension(true)) {
                    if (conclusion.getTermExtension(true)) {//termino mayor presenta mayor extension en la conclusion
                        violaciones.append("-El termino menor [t] presenta mayor extension en la conclusion que en la premisa.\n");
                        violations[2] = true;
                    }
                }
            } else {
                if (!premisaMenor.getTermExtension(false)) {
                    if (conclusion.getTermExtension(true)) {//termino mayor presenta mayor extension en la conclusion
                        violaciones.append("-El termino menor [t] presenta mayor extension en la conclusion que en la premisa.\n");
                        violations[2] = true;
                    }
                }
            }

            if (conclusion.getFirstTerm().equalsIgnoreCase(terminoMedio) ||
                    conclusion.getSecondTerm().equalsIgnoreCase(terminoMedio)) {
                violaciones.append("-El termino medio [M] no debe figurar en la conclusion.\n");
                violations[3] = true;
            }
            boolean tomadoDosVeces = false;
            boolean todaExtension = false;
            if ((terminoMedio.equalsIgnoreCase(premisaMayor.getFirstTerm()) ||
                    terminoMedio.equalsIgnoreCase(premisaMayor.getSecondTerm())) &&
                    (terminoMedio.equalsIgnoreCase(premisaMenor.getFirstTerm()) ||
                            terminoMedio.equalsIgnoreCase(premisaMenor.getSecondTerm()))) {
                tomadoDosVeces = true;
            }
            if (terminoMedio.equalsIgnoreCase(premisaMayor.getFirstTerm())) {
                if (premisaMayor.getTermExtension(true)) {
                    todaExtension = true;
                }
            } else {
                if (premisaMayor.getTermExtension(false)) {
                    todaExtension = true;
                }
            }
            if (terminoMedio.equalsIgnoreCase(premisaMenor.getFirstTerm())) {
                if (premisaMenor.getTermExtension(true)) {
                    todaExtension = true;
                }
            } else {
                if (premisaMenor.getTermExtension(false)) {
                    todaExtension = true;
                }
            }
            if (!(todaExtension && tomadoDosVeces)) {//todo verificar duda acerca de la regla...
                violaciones.append("-El termino medio [M] debe estar tomado dos veces o al menos una vez en toda su extension.\n");
                violations[4] = true;
            }
            if (((premisaMayor.getPartsExtension() == ExtensionEnum.E) || (premisaMayor.getPartsExtension() == ExtensionEnum.O)) &&
                    ((premisaMenor.getPartsExtension() == ExtensionEnum.E) || (premisaMenor.getPartsExtension() == ExtensionEnum.O))) {
                violaciones.append("-De dos premisas negativas, no se sigue nada.\n");
                violations[5] = true;
            }
            if (((premisaMayor.getPartsExtension() == ExtensionEnum.A) || (premisaMayor.getPartsExtension() == ExtensionEnum.I)) &&
                    ((premisaMenor.getPartsExtension() == ExtensionEnum.A) || (premisaMenor.getPartsExtension() == ExtensionEnum.I))) {
                if ((conclusion.getPartsExtension() == ExtensionEnum.E) || (conclusion.getPartsExtension() == ExtensionEnum.O)) {
                    violaciones.append("-Dos premisas afirmativas no pueden engendrar una negativa.\n");
                    violations[6] = true;
                }

            }
            //la conclusion sigue siempre la parte mas debil;
            ExtensionEnum premisaMayorExtension = premisaMayor.getPartsExtension();
            ExtensionEnum premisaMenorExtension = premisaMenor.getPartsExtension();
            boolean conclusionNegativa = false;
            boolean conclusionParticular = false;
            if (premisaMayorExtension == ExtensionEnum.E || premisaMayorExtension == ExtensionEnum.O ||
                    premisaMenorExtension == ExtensionEnum.E || premisaMenorExtension == ExtensionEnum.O) {
                conclusionNegativa = true;
            }
            if (premisaMayorExtension == ExtensionEnum.I || premisaMayorExtension == ExtensionEnum.O ||
                    premisaMenorExtension == ExtensionEnum.I || premisaMenorExtension == ExtensionEnum.O) {
                conclusionParticular = true;
            }

            if (conclusionNegativa && conclusionParticular && (conclusion.getPartsExtension() != ExtensionEnum.O)) {
                violaciones.append("-La conclusion siempre sigue la parte mas debil.\n");
                violations[7] = true;
            } else {
                if (conclusionNegativa && (conclusion.getPartsExtension() != ExtensionEnum.E) && (conclusion.getPartsExtension() != ExtensionEnum.O)) {
                    violaciones.append("-La conclusion siempre sigue la parte mas debil.\n");
                    violations[7] = true;
                } else {
                    if (conclusionParticular && (conclusion.getPartsExtension() != ExtensionEnum.I) && (conclusion.getPartsExtension() != ExtensionEnum.O)) {
                        violaciones.append("-La conclusion siempre sigue la parte mas debil.\n");
                        violations[7] = true;
                    }
                }
            }

            if (((premisaMayor.getPartsExtension() == ExtensionEnum.I) || (premisaMayor.getPartsExtension() == ExtensionEnum.O)) &&
                    ((premisaMenor.getPartsExtension() == ExtensionEnum.I) || (premisaMenor.getPartsExtension() == ExtensionEnum.O))) {
                violaciones.append("-De dos premisas particulares, no se sigue nada.\n");
                violations[8] = true;
            }
            if (violaciones.toString().equalsIgnoreCase("")) {
                violaciones.append("El silogismo ingresado es correcto!");
            }
        } else {
            if (premisaMayor == null) {
                violaciones.append("-Premisa mayor incompleta.\n");
            }
            if (premisaMenor == null) {
                violaciones.append("-Premisa menor incompleta.\n");
            }
            if (conclusion == null) {
                violaciones.append("-Conclusion incompleta.\n");
            }
        }
        return violaciones.toString();
    }

    /**
     * Permite obtener una de las premisas del silogismo;
     *
     * @param premisaTypeEnum;
     * @return Premisa;
     */
    public Premisa getPremisa(PremisaTypeEnum premisaTypeEnum) {
        switch (premisaTypeEnum) {
            case FIRST:
                return premisaMayor;
            case SECOND:
                return premisaMenor;
            default:
                return conclusion;
        }
    }

    /**
     * Completa el silogidmo en caso de ser posible;
     */
    public void complete() {
        if (canComplete()) {
            PremisaTypeEnum completed;
            Premisa premisa;
            String terminoMedio = "";
            String plural = "";
            String sonString = "es";
            String articuloPlural = "";

            terminoMedio = getTerminoMedio();
            if (premisaMayor == null) {
                completionAuxiliary(terminoMedio, getTerminoMayor(), PremisaTypeEnum.FIRST);
            } else {
                if (premisaMenor == null) {
                    completionAuxiliary(terminoMedio, getTerminoMenor(), PremisaTypeEnum.SECOND);
                } else {
                    //si la premisa mayor y menor se hallan completas, la premisa incompleta es la conclusion
                    premisa = buildPremisaPlural(getTerminoMenor(), getTerminoMayor());

                    setPremisa(premisa, PremisaTypeEnum.CONCLUSION);
                    completed = PremisaTypeEnum.CONCLUSION;
                    completeConversions(completed);
                }
            }
        }
    }

    private void completionAuxiliary(String firstTerm, String secondTerm, PremisaTypeEnum premisaTypeEnum) {
        boolean firstTermFirst = true;
        Premisa premisa;
        if (Math.random() < 0.5) {
            premisa = buildPremisaPlural(firstTerm, secondTerm);
        } else {
            premisa = buildPremisaPlural(secondTerm, firstTerm);
            firstTermFirst = false;
        }
        setPremisa(premisa, premisaTypeEnum);
        completeConversions(premisaTypeEnum);
        if (!analize().equalsIgnoreCase("El silogismo ingresado es correcto!")) {
            setPremisa(null, premisaTypeEnum);
            if (firstTermFirst) {
                premisa = buildPremisaPlural(secondTerm, firstTerm);
            } else {
                premisa = buildPremisaPlural(firstTerm, secondTerm);
            }
            setPremisa(premisa, premisaTypeEnum);
            completeConversions(premisaTypeEnum);
        }
    }

    /**
     * Devuelve la premisa usando los terminos en plural;
     *
     * @param firstTerm;
     * @param secondTerm;
     * @return Premisa;
     */
    private Premisa buildPremisaPlural(String firstTerm, String secondTerm) {
        String plural = "";
        String sonString = "es";
        String articuloPlural = "";
        if (LexicAnalizer.analizePlural(firstTerm)) {
            plural = "s";
            sonString = "son";
        }
        if (LexicAnalizer.analizeFemenino(null, firstTerm)) {
            if (!plural.equals("")) {
                articuloPlural = "las ";
            }
            return new Premisa("Toda" + plural + " " + articuloPlural + firstTerm + " " + sonString + " " + secondTerm);
        } else {
            if (!plural.equals("")) {
                articuloPlural = "los ";
            }
            return new Premisa("Todo" + plural + " " + articuloPlural + firstTerm + " " + sonString + " " + secondTerm);
        }
    }

    /**
     * Verifica si es posible completar el silogismo;
     *
     * @return boolean;
     */
    public boolean canComplete() {
        int terminos = 0;
        if (!getTerminoMayor().equals("")) {
            terminos++;
        }
        if (!getTerminoMedio().equals("")) {
            terminos++;
        }
        if (!getTerminoMenor().equals("")) {
            terminos++;
        }
        return terminos == 3;
    }

    /**
     * Toma una premisa y le otorga una extension valida;
     *
     * @param premisa;
     */
    private void completeConversions(PremisaTypeEnum premisa) {
        if (!analize().equals("El silogismo ingresado es correcto!")) {
            getPremisa(premisa).convert(ExtensionEnum.E);
            if (!analize().equals("El silogismo ingresado es correcto!")) {
                getPremisa(premisa).convert(ExtensionEnum.I);
                if (!analize().equals("El silogismo ingresado es correcto!")) {
                    getPremisa(premisa).convert(ExtensionEnum.O);
                }
            }
        }
    }

    /**
     * Metodo auxiliar de sugerencias;
     *
     * @return String;
     */
    private String premisaMayorYPremisaMenor() {
        switch (premisaMayor.getPartsExtension()) {
            case A:
                switch (premisaMenor.getPartsExtension()) {
                    case A:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_A_PREMISA_MENOR_A_PRIMERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_A_PREMISA_MENOR_A_TERCERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_A_PREMISA_MENOR_A_CUARTA_FIGURA);
                    case E:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_A_PREMISA_MENOR_E_SEGUNDA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_A_PREMISA_MENOR_E_CUARTA_FIGURA);
                    case I:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_A_PREMISA_MENOR_I_PRIMERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_A_PREMISA_MENOR_I_TERCERA_FIGURA);
                    case O:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_A_PREMISA_MENOR_O_SEGUNDA_FIGURA);
                }
                break;
            case E:
                switch (premisaMenor.getPartsExtension()) {
                    case A:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_E_PREMISA_MENOR_A_PRIMERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_E_PREMISA_MENOR_A_SEGUNDA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_E_PREMISA_MENOR_A_TERCERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_E_PREMISA_MENOR_A_CUARTA_FIGURA);
                    case E:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_E_PREMISA_MENOR_E_CUARTA_FIGURA);
                    case I:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_E_PREMISA_MENOR_I_PRIMERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_E_PREMISA_MENOR_I_SEGUNDA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_E_PREMISA_MENOR_I_TERCERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_E_PREMISA_MENOR_I_CUARTA_FIGURA);
                }
                break;
            case I:
                switch (premisaMenor.getPartsExtension()) {
                    case A:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_I_PREMISA_MENOR_A_TERCERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_I_PREMISA_MENOR_A_TERCERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_I_PREMISA_MENOR_A_CUARTA_FIGURA);
                    case E:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_I_PREMISA_MENOR_A_CUARTA_FIGURA);
                }
                break;
            case O:
                switch (premisaMenor.getPartsExtension()) {
                    case A:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_O_PREMISA_MENOR_A_TERCERA_FIGURA);
                }
                break;
        }
        return "";
    }

    /**
     * Metodo auxiliar de sugerencias;
     *
     * @return String;
     */
    private String premisaMayor() {
        switch (premisaMayor.getPartsExtension()) {
            case A:
                return MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MAYOR_A_PRIMERA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MAYOR_A_SEGUNDA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MAYOR_A_TERCERA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MAYOR_A_CUARTA_FIGURA);
            case E:
                return MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MAYOR_E_PRIMERA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MAYOR_E_SEGUNDA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MAYOR_E_TERCERA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MAYOR_E_CUARTA_FIGURA);
            case I:
                return MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MAYOR_I_TERCERA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MAYOR_I_CUARTA_FIGURA);
            case O:
                return MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MAYOR_O_TERCERA_FIGURA);
        }
        return "";
    }

    /**
     * Metodo auxiliar de sugerencias;
     *
     * @return String;
     */
    private String premisaMayorYConclusion() {
        switch (premisaMayor.getPartsExtension()) {
            case A:
                switch (conclusion.getPartsExtension()) {
                    case A:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_A_CONCLUSION_A_PRIMERA_FIGURA);
                    case E:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_A_CONCLUSION_E_SEGUNDA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_A_CONCLUSION_E_CUARTA_FIGURA);
                    case I:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_A_CONCLUSION_I_PRIMERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_A_CONCLUSION_I_TERCERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_A_CONCLUSION_I_CUARTA_FIGURA);
                    case O:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_A_CONCLUSION_O_SEGUNDA_FIGURA);
                }
            case E:
                switch (conclusion.getPartsExtension()) {
                    case E:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_E_CONCLUSION_E_PRIMERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_E_CONCLUSION_E_SEGUNDA_FIGURA);
                    case O:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_E_CONCLUSION_O_PRIMERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_E_CONCLUSION_O_SEGUNDA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_E_CONCLUSION_O_TERCERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_E_CONCLUSION_O_CUARTA_FIGURA);
                }
            case I:
                switch (conclusion.getPartsExtension()) {
                    case A:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_I_CONCLUSION_I_TERCERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_I_CONCLUSION_I_CUARTA_FIGURA);
                }
            case O:
                switch (conclusion.getPartsExtension()) {
                    case O:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MAYOR_O_CONCLUSION_O_TERCERA_FIGURA);
                }
        }
        return "";
    }

    /**
     * Metodo auxiliar de sugerencias;
     *
     * @return String;
     */
    private String premisaMenorYConclusion() {
        switch (premisaMenor.getPartsExtension()) {
            case A:
                switch (conclusion.getPartsExtension()) {
                    case A:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MENOR_A_CONCLUSION_A_PRIMERA_FIGURA);
                    case E:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MENOR_A_CONCLUSION_E_PRIMERA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MENOR_A_CONCLUSION_E_SEGUNDA_FIGURA);
                    case I:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MENOR_A_CONCLUSION_I_TERCERA_FIGURA) +
                                "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MENOR_A_CONCLUSION_I_CUARTA_FIGURA);
                    case O:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MENOR_A_CONCLUSION_O_TERCERA_FIGURA) +
                                "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MENOR_A_CONCLUSION_O_CUARTA_FIGURA);
                }
                break;
            case E:
                switch (conclusion.getPartsExtension()) {
                    case E:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MENOR_E_CONCLUSION_E_SEGUNDA_FIGURA)
                                + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MENOR_E_CONCLUSION_E_CUARTA_FIGURA);
                }
                break;
            case I:
                switch (conclusion.getPartsExtension()) {
                    case I:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MENOR_I_CONCLUSION_I_PRIMERA_FIGURA) +
                                "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MENOR_I_CONCLUSION_I_TERCERA_FIGURA);
                    case O:
                        return MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MENOR_I_CONCLUSION_O_PRIMERA_FIGURA) +
                                "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MENOR_I_CONCLUSION_O_SEGUNDA_FIGURA) +
                                "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MENOR_I_CONCLUSION_O_TERCERA_FIGURA) +
                                "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.PREMISA_MENOR_I_CONCLUSION_O_CUARTA_FIGURA);
                }
        }
        return "";
    }

    /**
     * Metodo auxiliar de sugerencias;
     *
     * @return String;
     */
    private String premisaMenor() {
        switch (premisaMenor.getPartsExtension()) {
            case A:
                return MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MENOR_A_PRIMERA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MENOR_A_SEGUNDA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MENOR_A_TERCERA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MENOR_A_CUARTA_FIGURA);
            case E:
                return MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MENOR_E_SEGUNDA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MENOR_E_CUARTA_FIGURA);
            case I:
                return MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MENOR_I_PRIMERA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MENOR_I_SEGUNDA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MENOR_I_TERCERA_FIGURA);
            case O:
                return MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_PREMISA_MENOR_O_SEGUNDA_FIGURA);
        }
        return "";
    }

    /**
     * Metodo auxiliar de sugerencias;
     *
     * @return String;
     */
    private String conclusion() {
        switch (conclusion.getPartsExtension()) {
            case A:
                return MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_CONCLUSION_A_PRIMERA_FIGURA);
            case E:
                return MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_CONCLUSION_E_PRIMERA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_CONCLUSION_E_SEGUNDA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_CONCLUSION_E_CUARTA_FIGURA);
            case I:
                return MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_CONCLUSION_I_PRIMERA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_CONCLUSION_I_TERCERA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_CONCLUSION_I_CUARTA_FIGURA);
            case O:
                return MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_CONCLUSION_O_PRIMERA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_CONCLUSION_O_SEGUNDA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_CONCLUSION_O_TERCERA_FIGURA)
                        + "\n" + MethodsLibrary.resourceBundle.getString(BundleExpressions.SOLO_CONCLUSION_O_CUARTA_FIGURA);
        }
        return "";
    }

    /**
     * This method looks for all terms, and checkes them to be the same, tham means not to have more than three
     * allowed terms. In other words: what stands for termino mayor, must be the same in the first premisa as in
     * conclusion. The same for the rest of the terms;
     *
     * @return true if there are only three real terms, false in other case;
     */
    private boolean validateTerminosIguales() {
        if (isComplete()) {
            if (premisaMayor.getFirstTerm().equalsIgnoreCase(conclusion.getSecondTerm()) ||
                    premisaMayor.getSecondTerm().equalsIgnoreCase(conclusion.getSecondTerm())) {
                if (premisaMayor.getFirstTerm().equalsIgnoreCase(premisaMenor.getFirstTerm()) ||
                        premisaMayor.getFirstTerm().equalsIgnoreCase(premisaMenor.getSecondTerm()) ||
                        premisaMayor.getSecondTerm().equalsIgnoreCase(premisaMenor.getFirstTerm()) ||
                        premisaMayor.getSecondTerm().equalsIgnoreCase(premisaMenor.getSecondTerm())) {
                    if (premisaMenor.getFirstTerm().equalsIgnoreCase(conclusion.getFirstTerm()) ||
                            premisaMenor.getSecondTerm().equalsIgnoreCase(conclusion.getFirstTerm())) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * Devuelve un String con la representacion XML del silogismo;
     *
     * @return String;
     */
    public String toXML() {
        StringBuffer stringBuffer = new StringBuffer(openTag());
        stringBuffer.append(premisaMayor.toXML());
        stringBuffer.append(premisaMenor.toXML());
        stringBuffer.append(conclusion.toXML());
        stringBuffer.append(closeTag());
        return stringBuffer.toString();
    }

    /**
     * Devuelve una representacion en String del silogismo;
     *
     * @return String;
     */
    public String toString() {
        StringBuffer stringBuffer = new StringBuffer("");
        if (getPremisa(PremisaTypeEnum.FIRST) != null) {
            stringBuffer.append(getPremisa(PremisaTypeEnum.FIRST).toString() + "\n");
        }
        if (getPremisa(PremisaTypeEnum.SECOND) != null) {
            stringBuffer.append(getPremisa(PremisaTypeEnum.SECOND).toString() + "\n");
        }
        stringBuffer.append("______________________________________________\n");
        if (getPremisa(PremisaTypeEnum.CONCLUSION) != null) {
            stringBuffer.append(getPremisa(PremisaTypeEnum.CONCLUSION).toString() + "\n");
        }
        return stringBuffer.toString();
    }

    /**
     * Interpreta un String XML y crea un objeto Sylogism acorde al XML;
     *
     * @param xml;
     * @return Sylogism;
     */
    public static Sylogism parseXML(String xml) {
        xml = xml.replace(openTag(), "");
        xml = xml.replace(closeTag(), "");
        xml = xml.replace(Premisa.openTag(), "");
        String[] premisaStrings = xml.split(Premisa.closeTag());
        Sylogism sylogism = new Sylogism();
        for (int j = 0; j < premisaStrings.length; j++) {
            if (j == 0) {
                sylogism.setPremisa(new Premisa(premisaStrings[0]), PremisaTypeEnum.FIRST);
            } else {
                if (j == 1) {
                    sylogism.setPremisa(new Premisa(premisaStrings[1]), PremisaTypeEnum.SECOND);
                } else {
                    sylogism.setPremisa(new Premisa(premisaStrings[2]), PremisaTypeEnum.CONCLUSION);
                }
            }
        }
        return sylogism;
    }

    /**
     * Devuelve el tag de apertura de la representacion XML del silogismo;
     *
     * @return String;
     */
    public static String openTag() {
        return "<sylogism>";
    }

    /**
     * Devuelve el tag de clausura de la representacion XML del silogismo;
     *
     * @return String;
     */
    public static String closeTag() {
        return "</sylogism>";
    }

    /**
     * Notifica de las violaciones en que incurre el silogismo;
     *
     * @return boolean[];
     */
    public boolean[] getViolations() {
        analize();
        return violations;
    }

    /**
     * Notifica si el silogismo formado es correcto;
     *
     * @return boolean;
     */
    public boolean isCorrect() {
        return !getViolations()[0] && !getViolations()[1] && !getViolations()[2] && !getViolations()[3] &&
                !getViolations()[4] && !getViolations()[5] && !getViolations()[6] && !getViolations()[7];
    }

    /**
     * Da a conocer a que modo puede reducirse el actual silogismo;
     *
     * @return SylogismReduceModesEnum;
     */
    public SylogismReduceModesEnum getReduceMode() {
        if (isComplete()) {
            switch (getFigure()) {
                case FIRST:
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.A) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.A) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.A)) {
                        return SylogismReduceModesEnum.BARBARA;
                    }
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.E) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.A) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.E)) {
                        return SylogismReduceModesEnum.CELARENT;
                    }
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.A) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.I) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.I)) {
                        return SylogismReduceModesEnum.DARII;
                    }
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.E) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.I) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.O)) {
                        return SylogismReduceModesEnum.FERIO;
                    }
                    break;
                case SECOND:
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.A) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.O) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.O)) {
                        return SylogismReduceModesEnum.BARBARA;
                    }
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.E) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.A) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.E)) {
                        return SylogismReduceModesEnum.CELARENT;
                    }
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.A) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.E) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.E)) {
                        return SylogismReduceModesEnum.CELARENT;
                    }
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.E) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.I) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.O)) {
                        return SylogismReduceModesEnum.FERIO;
                    }
                    break;
                case THIRD:
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.A) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.A) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.I)) {
                        return SylogismReduceModesEnum.DARII;
                    }
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.I) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.A) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.I)) {
                        return SylogismReduceModesEnum.DARII;
                    }
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.A) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.I) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.I)) {
                        return SylogismReduceModesEnum.DARII;
                    }
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.E) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.A) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.O)) {
                        return SylogismReduceModesEnum.FERIO;
                    }
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.O) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.A) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.O)) {
                        return SylogismReduceModesEnum.BARBARA;
                    }
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.E) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.I) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.O)) {
                        return SylogismReduceModesEnum.FERIO;
                    }
                    break;
                case FOURTH:
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.A) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.A) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.I)) {
                        return SylogismReduceModesEnum.BARBARA;
                    }
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.A) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.E) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.E)) {
                        return SylogismReduceModesEnum.CELARENT;
                    }
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.I) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.A) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.I)) {
                        return SylogismReduceModesEnum.DARII;
                    }
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.E) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.A) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.O)) {
                        return SylogismReduceModesEnum.FERIO;
                    }
                    if (premisaMayor.getPartsExtension().equals(ExtensionEnum.E) &&
                            premisaMenor.getPartsExtension().equals(ExtensionEnum.I) &&
                            conclusion.getPartsExtension().equals(ExtensionEnum.O)) {
                        return SylogismReduceModesEnum.FERIO;
                    }
            }
        }
        return SylogismReduceModesEnum.UNKNOWN;
    }

    /**
     * Efectua la reduccion de modo;
     */
    public void reduce() {
        SylogismReduceModesEnum reduceMode = getReduceMode();
        if (reduceMode != SylogismReduceModesEnum.UNKNOWN) {
            String terminoMayor = getTerminoMayor();
            String terminoMedio = getTerminoMedio();
            String terminoMenor = getTerminoMenor();
            premisaMayor = new Premisa(Premisa.buildPremisaString("Todo ", terminoMedio, " es ", terminoMayor));
            premisaMenor = new Premisa(Premisa.buildPremisaString("Todo ", terminoMenor, " es ", terminoMedio));
            conclusion = new Premisa(Premisa.buildPremisaString("Todo ", terminoMenor, " es ", terminoMayor));
            premisaMayor.convert(ExtensionEnum.E);
            premisaMenor.convert(ExtensionEnum.E);
            conclusion.convert(ExtensionEnum.E);
            switch (reduceMode) {
                case BARBARA:
                    premisaMayor.convert(ExtensionEnum.A);
                    premisaMenor.convert(ExtensionEnum.A);
                    conclusion.convert(ExtensionEnum.A);
                    break;
                case CELARENT:
                    premisaMenor.convert(ExtensionEnum.A);
                    break;
                case DARII:
                    premisaMayor.convert(ExtensionEnum.A);
                    premisaMenor.convert(ExtensionEnum.I);
                    conclusion.convert(ExtensionEnum.I);
                    break;
                case FERIO:
                    premisaMenor.convert(ExtensionEnum.I);
                    conclusion.convert(ExtensionEnum.O);
                    break;
            }
        }
    }
}
